/*
 * Copyright 2023-2023 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package net.yun789.javasipweb.config;

import gov.nist.javax.sdp.SessionDescriptionImpl;
import gov.nist.javax.sdp.parser.SDPAnnounceParser;
import gov.nist.javax.sip.address.SipUri;
import gov.nist.javax.sip.header.*;
import gov.nist.javax.sip.message.SIPRequest;
import net.yun789.javasipweb.dto.LoginUserDTO;
import net.yun789.javasipweb.handler.RequestHandler;
import net.yun789.javasipweb.sip.stack.UserTransaction;
import net.yun789.javasipweb.user.context.UserContextRepository;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.text.ParseException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;
import javax.annotation.PostConstruct;
import javax.sip.*;
import javax.sip.address.Address;
import javax.sip.address.AddressFactory;
import javax.sip.address.URI;
import javax.sip.header.*;
import javax.sip.message.MessageFactory;
import javax.sip.message.Request;
import javax.sip.message.Response;
@Component
public class SipPhone implements SipListener
{
    private static Logger log= LoggerFactory.getLogger(SipPhone.class);


//    /**
//     *登陆用户  key 为callId
//     */
//
//    private Map<String, LoginUserDTO> loginUserDTOMap = new ConcurrentHashMap<>(100);
//    /**
//     * 登陆用户
//     * key 为通话地址
//     */
//    private Map<String,List<LoginUserDTO>> loginUserDTOListMap =new ConcurrentHashMap<>(100);
    //ServerTransaction

    /**
     * 保存当前事务
     */
    private List<ServerTransaction> serverTransactionList =new CopyOnWriteArrayList<>();


//    private List<UserTransaction> userTransactionList =new CopyOnWriteArrayList<>();


//    /**
//     * 用户事务 key 事务id,值为相关会话事务的集合
//     */
//    private Map<String,List<UserTransaction>> userTransactionListMap = new ConcurrentHashMap<>();
//
//
//    /**
//     * 用户事务 key 事务id
//     */
//    private Map<String,UserTransaction> userTransactionMap = new ConcurrentHashMap<>();



//    private Map<String,String> onceMap = new ConcurrentHashMap<>();

    /**
     * 服务器侦听IP地址
     */
//    private String ipAddr = "127.0.0.1";


    /**
     * 内网ip地址
     */
    @Value("${address.internal}")
    private String addressInternal;
    /**
     *
     */
    @Value("${address.outernet}")
    private String addressOuternet;

    /**
     * 服务器侦听端口
     */
    @Value("${address.internal.port}")
    private int port = 9060;

    @Autowired
    private List<RequestHandler> requestHandlerList ;
    @Autowired
    private UserContextRepository userContextRepository;

    /**
     * 保存当前注册的用户
     */
    private static Hashtable<URI, URI> currUser = new Hashtable();


    /**
     * 获取登陆用户
     * @return
     */
    public Map<String,List<LoginUserDTO>> getLoginUserListMap(){
//        return loginUserDTOListMap;
        return null;
    }

    /**
     * 获取事务
     * @return
     */
    public Map<String,List<UserTransaction>> getUserTransactionListMap(){
//        return  this.userTransactionListMap;
        return null;
    }

    @Override
    public void processRequest(RequestEvent arg0)
    {
        Request request = arg0.getRequest();

        if (null == request)
        {
            System.out.println("processRequest request is null.");
            return;
        }
        System.out.println("processRequest:" + request.toString());
        if (Request.INVITE.equals(request.getMethod()))
        {
            processInvite(request, arg0);
        }
        else if (Request.REGISTER.equals(request.getMethod()))
        {
//            processRegister(request, arg0);
            RequestHandler requestHandler = getRequestHandler(request);
            requestHandler.handle(arg0);
        }
        else if (Request.SUBSCRIBE.equals(request.getMethod()))
        {
            processSubscribe(request);
        }
        else if (Request.ACK.equalsIgnoreCase(request.getMethod()))
        {
            processAck(request, arg0);
        }
        else if (Request.BYE.equalsIgnoreCase(request.getMethod()))
        {
            processBye(request, arg0);
        }
        else if (Request.CANCEL.equalsIgnoreCase(request.getMethod()))
        {
            processCancel(request, arg0);
        }
        else
        {
            System.out.println("no support the method!");
        }
    }

    private RequestHandler getRequestHandler(Request request){
        for(RequestHandler requestHandler:requestHandlerList){

            if(requestHandler.support(request.getMethod())){
                return requestHandler;
            }
        }
        return null;

    }

    @Override
    public void processDialogTerminated(DialogTerminatedEvent arg0) {
        // TODO Auto-generated method stub
        System.out.println("processDialogTerminated " + arg0.toString());
    }
    @Override
    public void processIOException(IOExceptionEvent arg0) {
        // TODO Auto-generated method stub
        System.out.println("processIOException " + arg0.toString());
    }




    /**
     * @author software
     * 注册定时器
     */
    class TimerTask extends Timer
    {
        /**
         * default constructor
         */
        public TimerTask()
        {

        }

        /**
         *  如果定时任务到，则删除该用户的注册信息
         */
        public void run()
        {

        }
    }











//    private synchronized List<LoginUserDTO> getLoginUserDTOList(String key ){
//
//        List<LoginUserDTO> loginUserDTOList = loginUserDTOListMap.computeIfAbsent(key, k -> new CopyOnWriteArrayList<>());
//
//        return loginUserDTOList;
//
//
//    }

    /**
     * 返回未授权
     * @param request
     * @param statusCode 401 or 407
     */
    private void returnNoAuth(Request request,int statusCode){
        if(statusCode!=401&&statusCode!=407){
            throw  new RuntimeException("statusCode must is  401 or 407");
        }

        try {
            Response response401 = msgFactory.createResponse(statusCode, request);
            WWWAuthenticateHeader wwwAuthenticateHeader=new WWWAuthenticate();
            wwwAuthenticateHeader.setRealm(addressOuternet);
            wwwAuthenticateHeader.setNonce(UUID.randomUUID().toString());
            wwwAuthenticateHeader.setAlgorithm("MD5");
            wwwAuthenticateHeader.setQop("auth");
            response401.addHeader(wwwAuthenticateHeader);
            ServerTransaction newServerTransaction = sipProvider.getNewServerTransaction(request);
            newServerTransaction.sendResponse(response401);
        }catch (Exception e){
            log.error(ExceptionUtils.getStackTrace(e));
            throw  new RuntimeException(e);
        }

    }

    /**
     * 处理invite请求
     * @param request 请求消息
     */
    private void processInvite(Request request, RequestEvent requestEvent)
    {
        if (null == request)
        {
            System.out.println("processInvite request is null.");
            return;
        }
        try
        {
            SIPRequest sipRequest = (SIPRequest) request;
            if(sipRequest.getContentLength().getContentLength()>0){
                log.info("getContentLength:{}",sipRequest.getContentLength().getContentLength());
                //解析sdp
                Object content = sipRequest.getContent();
                log.info("content.getClass():{}",content.getClass());

                log.info("content:{}",content);

                String contentStr=new String( (byte[])content,"utf-8");

                SDPAnnounceParser parser = new SDPAnnounceParser(contentStr);
                SessionDescriptionImpl parsedDescription = parser.parse();
                SessionDescriptionImpl sessiondescription = new SessionDescriptionImpl(parsedDescription);

                log.info("sessiondescription:{}",sessiondescription);



            }
//            sipRequest.
            //验证用户是登陆
            CallIdHeader callIdHeader = (CallIdHeader) request.getHeader(CallIdHeader.NAME);
//            LoginUserDTO loginUserDTO = loginUserDTOMap.get(callIdHeader.getCallId());
            LoginUserDTO loginUserDTO=userContextRepository.loadContext(request);
            if (loginUserDTO == null) {
//                boolean login = login(request);
                boolean login = userContextRepository.login(request);
                if(!login){
                    returnNoAuth(request, 407);
                    return;
                }
            }
            // 发送100 Trying
            ServerTransaction    serverTransactionId = requestEvent.getServerTransaction();
            List<UserTransaction> userTransactionListTemp;
            if (serverTransactionId == null)
            {
                serverTransactionId = sipProvider.getNewServerTransaction(request);
                callerDialog = serverTransactionId.getDialog();
                Response response = msgFactory.createResponse(Response.TRYING, request);
                serverTransactionId.sendResponse(response);
                serverTransactionList.add(serverTransactionId);

//                UserTransaction userTransaction = new UserTransaction();
//                userTransaction.setBranchId(serverTransactionId.getBranchId());
//                userTransaction.setCallId(callIdHeader.getCallId());
//                userTransaction.setTransaction(serverTransactionId);
//
//                userTransactionMap.put(serverTransactionId.getBranchId(),userTransaction);
//
//                synchronized (this){
//                    userTransactionListTemp = userTransactionListMap.computeIfAbsent(serverTransactionId.getBranchId(), k -> new CopyOnWriteArrayList<>());
//                    userTransactionListTemp.add(userTransaction);
//                }
            }else{
//                userTransactionListTemp=userTransactionListMap.get(serverTransactionId.getBranchId());
            }
            //查询目标地址
            URI reqUri = request.getRequestURI();
//            URI contactURI = currUser.get(reqUri);
//            List<LoginUserDTO> loginUserDTOList = loginUserDTOListMap.get(reqUri.toString());
//            log.info("loginUserDTOList:{}",loginUserDTOList);
//            URI contactURI = loginUserDTOList.get(loginUserDTOList.size() - 1).getContactURI();
            LoginUserDTO loginUserDTOTo = userContextRepository.loadContext(reqUri.toString());
            URI contactURI = loginUserDTOTo.getContactURI();


            log.info("被叫contactURI:{}",contactURI);


//            System.out.println("processInvite rqStr=" + reqUri + " contact=" + contactURI);

            //根据Request uri来路由，后续的响应消息通过VIA来路由
            Request cliReq = msgFactory.createRequest(request.toString());
            cliReq.setRequestURI(contactURI);

            Via callerVia = (Via)request.getHeader(Via.NAME);
            Via via = (Via) headerFactory.createViaHeader(addressOuternet, port, "UDP", callerVia.getBranch());

            // FIXME 需要测试是否能够通过设置VIA头域来修改VIA头域值
            cliReq.removeHeader(Via.NAME);
            cliReq.addHeader(via);

            // 更新contact的地址
            ContactHeader contactHeader = headerFactory.createContactHeader();

            ContactHeader contactHeaderFrom = (ContactHeader) request.getHeader(ContactHeader.NAME);
            SipUri uri = (SipUri) contactHeaderFrom.getAddress().getURI();
            String user=uri.getUser();
            Address address = addressFactory.createAddress("sip:"+user+"@" + addressOuternet +":"+ port);
            contactHeader.setAddress(address);
            contactHeader.setExpires(3600);
            cliReq.setHeader(contactHeader);
            CallIdHeader cliCallIdHeader = (CallIdHeader) cliReq.getHeader(CallIdHeader.NAME);
//            cliCallIdHeader.setCallId(UUID.randomUUID().toString());

            clientTransactionId = sipProvider.getNewClientTransaction(cliReq);
//            {
//                UserTransaction userTransaction = new UserTransaction();
//                userTransaction.setBranchId(clientTransactionId.getBranchId());
//                userTransaction.setCallId(cliCallIdHeader.getCallId());
//                userTransaction.setTransaction(clientTransactionId);
//
//                userTransactionMap.put(clientTransactionId.getBranchId(),userTransaction);
//
//                synchronized (this){
////                    List<UserTransaction> userTransactionListTemp = userTransactionListMap.computeIfAbsent(clientTransactionId.getBranchId(), k -> new CopyOnWriteArrayList<>());
//                    userTransactionListTemp.add(userTransaction);
//                    userTransactionListMap.put(clientTransactionId.getBranchId(),userTransactionListTemp);
//                }
//            }
            clientTransactionId.sendRequest();

//            System.out.println("processInvite clientTransactionId=" + clientTransactionId.toString());

//            System.out.println("send invite to callee: " + cliReq);
        }
        catch (TransactionUnavailableException e1)
        {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        catch (SipException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        catch (ParseException e)
        {
            e.printStackTrace();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    /**
     * 处理SUBSCRIBE请求
     * @param request 请求消息
     */
    private void processSubscribe(Request request)
    {
        if (null == request)
        {
//            System.out.println("processSubscribe request is null.");
            return;
        }
        ServerTransaction serverTransactionId = null;
        try
        {
            serverTransactionId = sipProvider.getNewServerTransaction(request);
        }
        catch (TransactionAlreadyExistsException e1)
        {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        } catch (TransactionUnavailableException e1)
        {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }

        try
        {
            Response response = null;
            response = msgFactory.createResponse(200, request);
            if (response != null)
            {
                ExpiresHeader expireHeader = headerFactory.createExpiresHeader(30);
                response.setExpires(expireHeader);
            }
//            System.out.println("response : " + response.toString());

            if(serverTransactionId != null)
            {
                serverTransactionId.sendResponse(response);
                serverTransactionId.terminate();
            }
            else
            {
//                System.out.println("processRequest serverTransactionId is null.");
            }

        }
        catch (ParseException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        catch (SipException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        catch (InvalidArgumentException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    /**
     * 处理BYE请求
     * @param request 请求消息
     */
    private void processBye(Request request, RequestEvent requestEvent)
    {
        if (null == request || null == requestEvent)
        {
            System.out.println("processBye request is null.");
            return;
        }
        Request byeReq = null;
        Dialog dialog = requestEvent.getDialog();
//        System.out.println("calleeDialog : " + calleeDialog);
//        System.out.println("callerDialog : " + callerDialog);
        try
        {
            if (dialog.equals(calleeDialog))
            {
                byeReq = callerDialog.createRequest(request.getMethod());
                ClientTransaction clientTran = sipProvider.getNewClientTransaction(byeReq);
                callerDialog.sendRequest(clientTran);
                calleeDialog.setApplicationData(requestEvent.getServerTransaction());
            }
            else if (dialog.equals(callerDialog))
            {
                byeReq = calleeDialog.createRequest(request.getMethod());
                ClientTransaction clientTran = sipProvider.getNewClientTransaction(byeReq);
                calleeDialog.sendRequest(clientTran);
                callerDialog.setApplicationData(requestEvent.getServerTransaction());
            }
            else
            {
                System.out.println("");
            }

//            System.out.println("send bye to peer:" + byeReq.toString());
        }
        catch (SipException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

    /**
     * 处理CANCEL请求
     * @param request 请求消息
     */
    private void processCancel(Request request)
    {
        if (null == request)
        {
            System.out.println("processCancel request is null.");
            return;
        }
    }

    /**
     * 处理INFO请求
     * @param request 请求消息
     */
    private void processInfo(Request request)
    {
        if (null == request)
        {
            System.out.println("processInfo request is null.");
            return;
        }
    }


    /**
     * 处理ACK请求
     * @param request 请求消息
     */
    private void processAck(Request request, RequestEvent requestEvent)
    {
        if (null == request)
        {
            System.out.println("processAck request is null.");
            return;
        }

        try
        {
//            Dialog dialog = requestEvent.getDialog();
//            Request ackRequest = null;
//            CSeq csReq = (CSeq)request.getHeader(CSeq.NAME);
//            ackRequest = dialog.createAck(csReq.getSeqNumber());
//            dialog.sendAck(ackRequest);
//            System.out.println("send ack to callee:" + ackRequest.toString());

            //转发Ack
//            Request cliReq = msgFactory.createRequest(request.toString());

//            ToHeader toHeader = (ToHeader) request.getHeader(ToHeader.NAME);
            //根据toheader找事务
//
//            ServerTransaction serverTransaction = requestEvent.getServerTransaction();

//            List<UserTransaction> userTransactionList = userTransactionListMap.get(serverTransaction.getBranchId());

            log.info("processAck:{}",request);
            //查询目标地址
            URI reqUri = request.getRequestURI();
//            List<LoginUserDTO> loginUserDTOList = loginUserDTOListMap.get(reqUri.toString());
//            log.info("loginUserDTOList:{}",loginUserDTOList);
//            URI contactURI = loginUserDTOList.get(loginUserDTOList.size() - 1).getContactURI();
            LoginUserDTO loginUserDTOTo = userContextRepository.loadContext(reqUri.toString());
            URI contactURI = loginUserDTOTo.getContactURI();
            log.info("被叫contactURI:{}",contactURI);
            Request cliReq = msgFactory.createRequest(request.toString());
            cliReq.setRequestURI(contactURI);

            Via callerVia = (Via)request.getHeader(Via.NAME);
            Via via = (Via) headerFactory.createViaHeader(addressOuternet, port, "UDP", callerVia.getBranch());

            // FIXME 需要测试是否能够通过设置VIA头域来修改VIA头域值
            cliReq.removeHeader(Via.NAME);
            cliReq.addHeader(via);

            // 更新contact的地址
            ContactHeader contactHeader = headerFactory.createContactHeader();

            ContactHeader contactHeaderFrom = (ContactHeader) request.getHeader(ContactHeader.NAME);
            SipUri uri = (SipUri) contactHeaderFrom.getAddress().getURI();
            String user=uri.getUser();
            Address address = addressFactory.createAddress("sip:"+user+"@" + addressOuternet +":"+ port);
            contactHeader.setAddress(address);
            contactHeader.setExpires(3600);
            cliReq.setHeader(contactHeader);
            CallIdHeader cliCallIdHeader = (CallIdHeader) cliReq.getHeader(CallIdHeader.NAME);
            sipProvider.sendRequest(cliReq);
//            cliCallIdHeader.setCallId(UUID.randomUUID().toString());
//            Via callerVia = (Via)request.getHeader(Via.NAME);
//            List<UserTransaction> userTransactionList = userTransactionListMap.get(callerVia.getBranch());

//            ClientTransaction clientTransaction= (ClientTransaction) userTransactionList.stream().filter(e->!e.getTransaction().getBranchId().equals(callerVia.getBranch())).findFirst().get().getTransaction();
//            sipProvider.sendRequest();
//            clientTransaction.
//            clientTransactionId = sipProvider.getNewClientTransaction(cliReq);
//
//            clientTransactionId.sendRequest();
//            Dialog dialog = clientTransaction.getDialog();
//            Request ackRequest = null;
//            CSeq csReq = (CSeq)request.getHeader(CSeq.NAME);
//            ackRequest = dialog.createAck(csReq.getSeqNumber());
//            dialog.sendAck(ackRequest);



        }
        catch (Exception e)
        {
            // TODO Auto-generated catch block

            log.error(ExceptionUtils.getStackTrace(e));
        }


    }

    /**
     * 处理CANCEL消息
     * @param request
     * @param requestEvent
     */
    private void processCancel(Request request, RequestEvent requestEvent)
    {
        // 判断参数是否有效
        if (request == null || requestEvent == null)
        {
            System.out.println("processCancel input parameter invalid.");
            return;
        }

        try
        {
            // 发送CANCEL 200 OK消息
            Response response = msgFactory.createResponse(Response.OK, request);
            ServerTransaction cancelServTran = requestEvent.getServerTransaction();
            if (cancelServTran == null)
            {
                cancelServTran = sipProvider.getNewServerTransaction(request);
            }
            cancelServTran.sendResponse(response);

            // 向对端发送CANCEL消息
            Request cancelReq = null;
            Request inviteReq = clientTransactionId.getRequest();
            List list = new ArrayList();
            Via viaHeader = (Via)inviteReq.getHeader(Via.NAME);
            list.add(viaHeader);

            CSeq cseq = (CSeq)inviteReq.getHeader(CSeq.NAME);
            CSeq cancelCSeq = (CSeq)headerFactory.createCSeqHeader(cseq.getSeqNumber(), Request.CANCEL);
            cancelReq = msgFactory.createRequest(inviteReq.getRequestURI(),
                    inviteReq.getMethod(),
                    (CallIdHeader)inviteReq.getHeader(CallIdHeader.NAME),
                    cancelCSeq,
                    (FromHeader)inviteReq.getHeader(From.NAME),
                    (ToHeader)inviteReq.getHeader(ToHeader.NAME),
                    list,
                    (MaxForwardsHeader)inviteReq.getHeader(MaxForwardsHeader.NAME));
            ClientTransaction cancelClientTran = sipProvider.getNewClientTransaction(cancelReq);
            cancelClientTran.sendRequest();
        }
        catch (ParseException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        catch (TransactionAlreadyExistsException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        catch (TransactionUnavailableException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        catch (SipException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        catch (InvalidArgumentException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }


//    private ServerTransaction serverTransactionId = null;
    /* (non-Javadoc)
     * @see javax.sip.SipListener#processRequest(javax.sip.RequestEvent)
     */


    /**
     * 主叫对话
     */
    private Dialog calleeDialog = null;

    /**
     * 被叫对话
     */
    private Dialog callerDialog = null;

    /**
     *
     */
    ClientTransaction clientTransactionId = null;

    /**
     * 处理BYE响应消息
     * @param response
     * @param responseEvent
     */
    private void doByeResponse(Response response, ResponseEvent responseEvent)
    {
        Dialog dialog = responseEvent.getDialog();

        try
        {
            Response byeResp = null;
            if (callerDialog.equals(dialog))
            {
                ServerTransaction servTran = (ServerTransaction)calleeDialog.getApplicationData();
                byeResp = msgFactory.createResponse(response.getStatusCode(), servTran.getRequest());
                servTran.sendResponse(byeResp);
            }
            else if (calleeDialog.equals(dialog))
            {
                ServerTransaction servTran = (ServerTransaction)callerDialog.getApplicationData();
                byeResp = msgFactory.createResponse(response.getStatusCode(), servTran.getRequest());
                servTran.sendResponse(byeResp);
            }
            else
            {

            }
//            System.out.println("send bye response to peer:" + byeResp.toString());
        }
        catch (ParseException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SipException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InvalidArgumentException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    /* (non-Javadoc)
     * @see javax.sip.SipListener#processResponse(javax.sip.ResponseEvent)
     *
     */
    @Override
    public void processResponse(ResponseEvent arg0)
    {
        // FIXME 需要判断各个响应对应的是什么请求
        Response response = arg0.getResponse();
//
//        System.out.println("recv the response :" +  response.toString());
//        System.out.println("respone to request : " + arg0.getClientTransaction().getRequest());

        if (response.getStatusCode() == Response.TRYING)
        {
//            System.out.println("The response is 100 response.");
            return;
        }

        try
        {
            ClientTransaction clientTran;

//            log.info("clientTran :{}",clientTran);

            ServerTransaction serverTransactionId=null ;
            clientTran=   arg0.getClientTransaction();
        {
//                log.info("clientTran is null ");
//                log.info("response:{}",response);
//                ViaHeader viaHeader = (ViaHeader) response.getHeader(ViaHeader.NAME);
//                clientTran= (ClientTransaction) userTransactionMap.get(viaHeader.getBranch()).getTransaction();
//                serverTransactionId= (ServerTransaction) userTransactionListMap.get(viaHeader.getBranch()).stream().filter(e->e.getTransaction()!=clientTran).findFirst().get().getTransaction();
//            }
//                {
                for (ServerTransaction serverTransactionTemp : serverTransactionList) {
                    //
                    if(clientTran.getBranchId().equals(serverTransactionTemp.getBranchId())){
                        serverTransactionId=serverTransactionTemp;
                        break;
                    }
                }
            }



            if (Request.INVITE.equalsIgnoreCase(clientTran.getRequest().getMethod()))
            {
                int statusCode = response.getStatusCode();
                Response callerResp = null;

                callerResp = msgFactory.createResponse(statusCode, serverTransactionId.getRequest());

                // 更新contact头域值，因为后面的消息是根据该URI来路由的
                ContactHeader contactHeaderFrom = (ContactHeader) arg0.getResponse().getHeader(ContactHeader.NAME);
                FromHeader fromHeader = (FromHeader) arg0.getResponse().getHeader(FromHeader.NAME);
                SipUri uri= (SipUri) (contactHeaderFrom==null?fromHeader.getAddress().getURI():contactHeaderFrom.getAddress().getURI());

                String user = uri.getUser();

                ContactHeader contactHeader = headerFactory.createContactHeader();
                Address address = addressFactory.createAddress("sip:"+user+"@"+addressOuternet+":"+port);
                contactHeader.setAddress(address);
                contactHeader.setExpires(3600);
                callerResp.addHeader(contactHeader);

                // 拷贝to头域
                ToHeader toHeader = (ToHeader)response.getHeader(ToHeader.NAME);
                callerResp.setHeader(toHeader);

                // 拷贝相应的消息体
                ContentLength contentLen = (ContentLength)response.getContentLength();
                if (contentLen != null && contentLen.getContentLength() != 0)
                {
                    ContentType contentType = (ContentType)response.getHeader(ContentType.NAME);
//                    System.out.println("the sdp contenttype is " + contentType);

                    callerResp.setContentLength(contentLen);
                    //callerResp.addHeader(contentType);
                    Object content = response.getContent();
                    callerResp.setContent(response.getContent(), contentType);
                }
                else
                {
                    System.out.println("sdp is null.");
                }
                if (serverTransactionId != null)
                {
                    callerDialog = serverTransactionId.getDialog();
                    calleeDialog = clientTran.getDialog();
                    serverTransactionId.sendResponse(callerResp);
//                    System.out.println("callerDialog=" + callerDialog);
//                    System.out.println("serverTransactionId.branch=" + serverTransactionId.getBranchId());
                }
                else
                {
                    System.out.println("serverTransactionId is null.");
                }

                System.out.println("send response to caller : " + callerResp.toString());
            }
            else if (Request.BYE.equalsIgnoreCase(clientTran.getRequest().getMethod()))
            {
                doByeResponse(response, arg0);
            }
            else if (Request.CANCEL.equalsIgnoreCase(clientTran.getRequest().getMethod()))
            {
                //doCancelResponse(response, arg0);
            }
            else
            {

            }


        }
        catch (ParseException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        catch (SipException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        catch (InvalidArgumentException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        catch (Exception ex)
        {
            ex.printStackTrace();
        }

    }

    private void doCancelResponse(Response response, ResponseEvent responseEvent)
    {
        //FIXME  需要验证参数的有效性
        ServerTransaction servTran = (ServerTransaction)callerDialog.getApplicationData();
        Response cancelResp;
        try
        {
            cancelResp = msgFactory.createResponse(response.getStatusCode(), servTran.getRequest());
            servTran.sendResponse(cancelResp);
        }
        catch (ParseException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        catch (SipException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        catch (InvalidArgumentException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
    @Override
    public void processTimeout(TimeoutEvent arg0)
    {
        // TODO Auto-generated method stub
        System.out.println(" processTimeout " + arg0.toString());
    }
    @Override
    public void processTransactionTerminated(TransactionTerminatedEvent arg0) {
        // TODO Auto-generated method stub
        System.out.println(" processTransactionTerminated " + arg0.getClientTransaction().getBranchId()
                + " " + arg0.getServerTransaction().getBranchId());
    }

    @Autowired
    private  SipStack sipStack = null;
    @Autowired
    private  AddressFactory addressFactory = null;
    @Autowired
    private  MessageFactory msgFactory = null;
    @Autowired
    private  HeaderFactory headerFactory = null;
    @Autowired
    private  SipProvider sipProvider = null;

    @PostConstruct
    public void init() throws TooManyListenersException {
        sipProvider.addSipListener(this);
    }

    /**
     * 程序入口
     * @param args
     */
    public static void main(String []args)
    {
//        new SipPhone().init();
    }

}